#!/usr/bin/env bash

############################################################################
# File Name: install_mysql.sh
# Version: V1.0
# Author: Brian Hsiung
# Created Time : 2025-01-23 16:37:00
# Description: MySQL部署，如果将其部署在中间件服务器，
# 请将INNODB_BUFFER_POOL_SIZE设置为1G, innodb_buffer_pool_instances设置为1
###########################################################################

# 调试跟踪（-e: 与错退出， -u: 捕获未定义的变量， -x: 调试模式，在执行每个命令前，将其打印到标准错误输出）
# set -eux

# 主库IP（方便设置从库连接主库导出全量备份）
declare -r MYSQL_MASTER_IP="192.168.1.1"

# 数据库用户
declare -r MYSQL_USER="mysql"
# 数据库版本
declare -r MYSQL_VERSION="8.0.39"
# glibc (2.17, 2.28)
declare -r MYSQL_GLIBC="glibc2.28"
# server-id (取主机IP最后一段)
MYSQL_ID="$(hostname -I|awk '{print $1}'|cut -d '.' -f4)"
declare -r MYSQL_ID
# MySQL 端口
declare -r MYSQL_PORT="3306"
# 软连接目录
declare -r MYSQL_BASE_DIR="/usr/local/mysql"
# 数据目录 /data 或 /opt
declare -r MYSQL_DATA_BASE="/data/mysql"
# 数据存储目录
declare -r MYSQL_DATA_DIR="$MYSQL_DATA_BASE/data"
# 日志存储目录
declare -r MYSQL_LOG_DIR="$MYSQL_DATA_BASE/log"
# BINLOG存储目录
declare -r MYSQL_BINLOG_DIR="$MYSQL_DATA_BASE/binlog"
# 临时文件存储目录（一定要定义，否则在默认/tmp, 某些情况下会写满/tmp从而导致异常）
declare -r MYSQL_TMP_DIR="$MYSQL_DATA_BASE/tmp"
# 最大连接数
declare -r MAX_CONNECTIONS=3000
# binlog保留时间（7天）, 按秒计算
declare -r BINLOG_EXPIRE=604800
# 数据库root权限密码
declare -r MYSQL_ROOT_PASSWORD='KXhz5u6!kY@QZvHdbjJEGj'
# 数据库高权限账号密码
declare -r MYSQL_ADMIN_PASSWORD='WM56HP!RiT@vHt1KTPsGkE'
# 数据库账号nacos_server密码（用于部署Nacos）
declare -r MYSQL_NACOS_PASSWORD='Wm56lp!RiT@vht1KgpsGkE'
# 数据库账号repl_user密码（用于配置主从复制）
declare -r MYSQL_REPL_PASSWORD='lpRiTv45ht1K!gp@sGkE'

# 阿里云OSS存储地址
declare -r OSS_BASE_URL="https://brianhsiung.oss-cn-hangzhou.aliyuncs.com"

# innodb配置配置(这里取服务器内存的75%)
# 缓冲池总大小 ≤ 8GB​​时，实例数使用默认值（或CPU核心数的一半）
# 缓冲池总大小 > 8GB​​时，根据CPU核心数设置，例如：16核32GB的服务器，设置缓冲池24GB，实例数12，每个实例分配2GB内存
MEMORY_TOTAL=$(awk 'BEGIN{IGNORECASE=1} /MemTotal/{print $(NF-1)}' /proc/meminfo)
INNODB_BUFFER_POOL_SIZE=$(awk -v limit="$MEMORY_TOTAL" 'BEGIN {print limit / 1024 / 1024 * 0.75}' | cut -d '.' -f1)
INNODB_BUFFER_POOL_INSTANCES=$(awk -v cpus="$(grep -c "processor" /proc/cpuinfo)" 'BEGIN {print cpus / 2}' | cut -d '.' -f1)

if [ "$INNODB_BUFFER_POOL_INSTANCES" -eq 0 ]; then
    INNODB_BUFFER_POOL_INSTANCES=1
fi

if [ "$INNODB_BUFFER_POOL_SIZE" -eq 0 ]; then
    INNODB_BUFFER_POOL_SIZE=1
fi


WORK_DIR="$(cd "$(dirname "$0")" && pwd)"
cd "$WORK_DIR" || exit

##############################################
# 日志函数
##############################################
log_info()    { echo -e "\033[34m[INFO] $*\033[0m"; }
log_warn()    { echo -e "\033[33m[WARNING] $*\033[0m"; }
log_success() { echo -e "\033[32m[SUCCESS] $*\033[0m"; }
log_error()   { echo -e "\033[31m[ERROR] $*\033[0m"; exit 1; }

log_info "数据库安装目录：$MYSQL_BASE_DIR"
log_info "数据库数据存储目录：$MYSQL_DATA_DIR"
log_info "数据库日志目录：$MYSQL_LOG_DIR"
log_info "数据库BINLOG目录: $MYSQL_BINLOG_DIR"
log_info "数据库临时文件目录：$MYSQL_TMP_DIR"

##############################################
# 检查依赖
##############################################
check_dependency() {

    local -a required_cmds=("wget" "tar" "groupadd" "useradd")
    local missing=()

    log_info "检查依赖命令: ${required_cmds[*]}"
    for cmd in "${required_cmds[@]}"; do
        if ! command -v "$cmd" &>/dev/null; then
            missing+=("$cmd")
        fi
    done

    ((${#missing[@]})) && log_error "缺失依赖命令: ${missing[*]}"
}

##############################################
# 获取Glibc版本
##############################################
get_glibc_version() {
    local glibc_version
    glibc_version=$(ldd --version | awk 'NR==1{print $NF}')
    log_info "GLIBC版本: $glibc_version"
}

##############################################
# 设置系统参数
##############################################
set_system_parameters() {
    local sysctl_conf="/etc/sysctl.conf"
    local sysctl_params=(
        "net.core.somaxconn = 4096"
        "net.ipv4.tcp_max_syn_backlog = 8192"
        "vm.swappiness = 0"
    )

    log_info "设置系统参数: $sysctl_conf"
    /bin/cp -af /etc/sysctl.conf "/etc/sysctl.conf.bak.$(date '+%Y%m%d%H%M%S')"

    for param in "${sysctl_params[@]}"; do
        if ! grep -q "$param" "$sysctl_conf"; then
            echo "$param" >> "$sysctl_conf"
            log_info "添加参数: $param"
        else
            log_success "参数已存在: $param"
        fi
    done
    sysctl -p

    # 透明大页设置
    log_info "透明大页设置"
    tee /sys/kernel/mm/transparent_hugepage/{enabled,defrag} <<< never
    # 开机启动配置
    grep -q 'transparent_hugepage' /etc/rc.d/rc.local || cat << EOF >> /etc/rc.d/rc.local
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
EOF
    chmod +x /etc/rc.d/rc.local

    # 文件描述符限制
    local limits_conf="/etc/security/limits.conf"
    if ! grep -q "root.*nofile" "${limits_conf}"; then
        log_info "设置文件描述符限制"
        cat << EOF >> "${limits_conf}"
root soft nofile 65535
root hard nofile 65535
* soft nofile 65535
* hard nofile 65535
EOF
    fi

}

##############################################
# 提示用户
##############################################
prompt_user() {
    local message=$1
    while :
    do
        read -r -p "$message [Y/n]: " option
        # 转换为小写，需要使用bash, 不能使用sh
        case "${option}" in
            y|Y)
                echo "确认使用该目录"
                break
                ;;
            n|N)
                echo "操作已取消"
                exit 1
                ;;
            *)
                echo "无效输入，请输入 Y(y) 或 N(n)"
                ;;
        esac
    done
}

##############################################
# 设置目录权限（递归检查上级目录）
##############################################
set_parent_permissions() {
    ### 某些等保三服务器默认新建的的目录权限为700，导致服务无法启动，所以需要遍历上级目录，将权限修改为755
    # 获取真实目录
    local target_dir
    target_dir=$(realpath "$1")
    # 获取上级目录
    local current_dir
    current_dir=$(dirname "$target_dir")

    # 做个判断，避免进入死循环
    [ -d "$target_dir" ] || log_error "目录不存在 [$target_dir]"

    while [[ "$current_dir" != "/" ]]; do
        # 跳过不存在的目录
        if [[ ! -d "$current_dir" ]]; then
            log_warn "警告: 目录不存在 [$current_dir]"
            current_dir=$(dirname "$current_dir")
            continue
        fi
        
        # 获取当前目录权限
        local perm_oct
        perm_oct=$(stat -c '%a' "$current_dir")
        
        if [[ "$perm_oct" != "755" ]]; then
            log_info "正在设置权限: [755] -> $current_dir"
            if ! chmod 755 "$current_dir"; then
                log_error "错误: 无法设置目录权限 [$current_dir]"
            fi
        else
            log_success "权限正确 [755]: $current_dir"
        fi

        # 向上一级目录
        current_dir=$(dirname "$current_dir")
    done
}

##############################################
# 检查mysql存储目录
##############################################
check_mysql_dir() {
    local mysql_dir=$1
    if [ ! -d "$mysql_dir" ]; then
        log_info "创建目录: $mysql_dir"
        mkdir -p "$mysql_dir"
    elif [ "$(ls -A "$mysql_dir")" ]; then
        prompt_user "目录 $mysql_dir 存在且不为空，是否继续？"
    fi
}

##############################################
# 初始化
##############################################
init_env () {

    #check for root user
    [ "$EUID" -ne 0 ] && log_error "请使用root账号执行此脚本！"

    ### 设置系统参数
    set_system_parameters

    if ss -tuln | grep -q ":$MYSQL_PORT "; then
        log_error "端口 $MYSQL_PORT 被占用，请检查服务是否已经存在"
    fi

    # 防火墙开放端口
    if systemctl is-active --quiet firewalld; then
        firewall-cmd --zone=public --add-port="$MYSQL_PORT"/tcp --permanent
        firewall-cmd --reload
    fi

    # yum remove -y mariadb mariadb-server
    if rpm -qa | grep mariadb >/dev/null 2>&1; then
        log_warn "mariadb相关包: \n $(rpm -qa | grep mariadb)"
        # while true || while :
        while :
        do
            read -r -p "服务器上存在mariadb安装包，是否要自动删除 [Y/n]: " option
            case "${option}" in
                Y|y)
                    log_warn "自动删除包"
                    rpm -e --nodeps "$(rpm -qa | grep mariadb)"
                    break
                    ;;
                N|n)
                    echo "用户进行手动删除！"
                    exit 1
                    ;;
                *)
                    echo "无效输入，请输入 Y(y) 或 N(n)"
                    ;;
            esac
        done
    fi
    
    ### 添加用户
    if ! getent group "$MYSQL_USER" >/dev/null; then
        log_info "创建用户组: $MYSQL_USER"
        groupadd -r "$MYSQL_USER"
    fi

    if ! getent passwd "$MYSQL_USER" >/dev/null 2>&1; then
        log_info "创建用户: $MYSQL_USER"
        useradd -r -M -g "$MYSQL_USER" "$MYSQL_USER" -s /sbin/nologin
    fi

    ### 创建目录
    log_info "创建目录: $MYSQL_DATA_BASE"
    [ -d "$MYSQL_DATA_BASE" ] || mkdir -p "$MYSQL_DATA_BASE"
    check_mysql_dir "$MYSQL_DATA_DIR"
    check_mysql_dir "$MYSQL_LOG_DIR"
    check_mysql_dir "$MYSQL_BINLOG_DIR"
    check_mysql_dir "$MYSQL_TMP_DIR"

    ### 设置目录权限
    set_parent_permissions "$MYSQL_DATA_BASE"
}

##############################################
# 配置文件
##############################################
init_conf() {
    log_info "初始化配置文件 /etc/my.cnf"
cat > /etc/my.cnf << EOF
[client]
# 命令行或客户端没有显示指定端口号时，此值将用作默认值，一般与mysqld中的端口保持一致
port = $MYSQL_PORT
socket = $MYSQL_LOG_DIR/mysql.sock

[mysql]
# 关闭自动补全
no-auto-rehash

[mysqld]
# 运行用户
user = $MYSQL_USER
# 端口号
port = $MYSQL_PORT
# 每个服务器唯一
server-id = $MYSQL_ID
# 禁止DNS解析，提高访问速度
skip_name_resolve=1

basedir = $MYSQL_BASE_DIR
datadir = $MYSQL_DATA_DIR
tmpdir = $MYSQL_TMP_DIR

socket = $MYSQL_LOG_DIR/mysql.sock
pid-file = $MYSQL_LOG_DIR/mysqld.pid
log-error = $MYSQL_LOG_DIR/mysqld.log

# 从库复制时，跳过以下错误，生产环境有风险，不建议使用
# 1032: 记录不存在
# 1062: 主键冲突
# 1146: 表不存在
# slave_skip_errors = 1032,1062,1146

# 默认200，默认取max-connections的值，一般不需要显式设置
# back_log=2000
# 默认32768，设置事物缓存大小
binlog_cache_size=4M
# 默认CRC32
# binlog_checksum=CRC32
# 默认为ON
# binlog_order_commits=ON
# 默认utf8
character_set_server=utf8mb4
collation-server = utf8mb4_general_ci
# concurrent_insert，查一查（0，1，2）
connect_timeout=60
default_storage_engine=InnoDB
default_time_zone = +8:00
explicit_defaults_for_timestamp=true

# authentication_policy = mysql_native_password

###################################################### Innodb ######################################################
# 为内存的60%～80%
innodb_buffer_pool_size=${INNODB_BUFFER_POOL_SIZE}G
# 实例数应与CPU核心数相近，但不超过64（MySQL的实例数上限）。例如，32核服务器可设置16-32个实例，32核服务器+64GB缓冲池 → 实例数建议32（若总缓冲池为16GB则取16）。
# {LEAST(DBInstanceClassMemory/1GB, 64)}, 超过64则取64，小于64则取实际值，需要保证每个缓冲池实例至少1GB
# https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html#sysvar_innodb_buffer_pool_instances
innodb_buffer_pool_instances=${INNODB_BUFFER_POOL_INSTANCES}
# 默认16MB，较大的日志缓冲区允许运行大型事物，而无需在事物提交前将日志写入磁盘
innodb_log_buffer_size=128M
# 以下两个值MySQL默认启用
innodb_buffer_pool_load_at_startup=1
innodb_buffer_pool_dump_at_shutdown=1
# 默认为fsync
innodb_flush_method=O_DIRECT
#如果打开参数innodb_flush_sync, checkpoint时，flush操作将由page cleaner线程来完成，此时page cleaner会忽略io capacity的限制，进入激烈刷脏
innodb_flush_sync = 0
innodb_flush_neighbors = 0
# 默认200（阿里云：20000）
innodb_io_capacity=800
# 默认2000（阿里云：40000）
innodb_io_capacity_max=20000
# 默认1024
innodb_lru_scan_depth=1024
# 默认为10
# innodb_max_dirty_pages_pct_lwm=0
innodb_max_dirty_pages_pct = 50
# 默认1073741824
innodb_max_undo_log_size=2G
# 默认134217728
innodb_online_alter_log_max_size=2G
# 默认4000
innodb_open_files=65535
innodb_file_per_table=1
# 默认为1
innodb_page_cleaners=8
# 默认为4
innodb_purge_threads=8
# 默认为4
innodb_read_io_threads=8
# 默认为4
innodb_write_io_threads=8
# 默认采用半同步数据复制方式（数据安全性最高）
# 事务提交时，把事务日志从缓存区写到日志文件中，并且立刻写入到磁盘上。
innodb_flush_log_at_trx_commit=1
# 事务提交后，将二进制日志文件写入磁盘并立即刷新，相当于同步写入磁盘，不经过系统缓存。
sync_binlog=1
innodb_log_files_in_group=3
innodb_log_file_size=2G
innodb_data_file_path=ibdata1:1G:autoextend
######################################################## Innodb ######################################################
key_buffer_size=128M
sort_buffer_size=8M
join_buffer_size=4M
read_buffer_size=4M
read_rnd_buffer_size=8M
# 默认为OFF
log_queries_not_using_indexes=1
log_timestamps=system
# 表名忽略大小写
lower_case_table_names=1
# 默认1073741824
max_allowed_packet=1G
# 默认100
max_connect_errors=100
# 默认1024
max_error_count=1024
# 默认16777216
max_heap_table_size=32M
# 默认4096
max_length_for_sort_data=1024
# 默认16382
max_prepared_stmt_count=1048576
# 默认8210
open_files_limit=65535
# 默认4000
table_open_cache=8000
# 默认16
table_open_cache_instances=64
# 默认10
thread_cache_size=600
# 默认1048576
thread_stack=512K
# 默认16777216
tmp_table_size=32M
transaction_isolation=READ-COMMITTED
# 默认28800
wait_timeout=86400

table_definition_cache=8000

max_connections = $MAX_CONNECTIONS

binlog_format=ROW
max_binlog_size=1G
binlog_expire_logs_seconds = $BINLOG_EXPIRE
log_bin = $MYSQL_BINLOG_DIR/mysql-bin

master_info_repository=TABLE
relay_log_info_repository=TABLE

slave-parallel-type=LOGICAL_CLOCK
slave-parallel-workers=4

# 启用gtid复制
gtid_mode=on
enforce_gtid_consistency=true
binlog_checksum = 1
# 启用中继日志自动恢复功能，当服务器上的复制线程因意外中断或其它原因停止时，该参数可以帮助确保数据的一致性，并尝试从中断点继续复制
relay_log_recovery=1
# 从库保存主库复制过来的二进制日志（Binary Log）事件的日志文件
relay_log = $MYSQL_LOG_DIR/relay_log
slave_type_conversions=ALL_NON_LOSSY,ALL_LOSSY
# 默认为OFF, 从服务器只执行主服务器发送的事件，但不会将这些事件记录到自己的二进制日志中，附加到此从服务器的其他服务器不会收到从主服务器复制的更新。
log_slave_updates=ON

# 开启慢SQL记录
slow_query_log = on
long_query_time = 5       # 记录慢SQL的时间
slow_query_log_file = $MYSQL_LOG_DIR/slow-mysql-query.log

# 密码验证方式
authentication_policy = mysql_native_password

# 去掉默认值里的ONLY_FULL_GROUP_BY
sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'

# 从库时，建议配置主从同步后设置只读
# read_only=1
EOF

    chmod 644 /etc/my.cnf
}

##############################################
# 安装myql
##############################################
install_mysql() {

    local arch
    local arch_type
    local mysql_name
    local mysql_pkg_name
    local mysql_target_dir

    arch="$(uname -m)"
    case "$arch" in
        aarch64|arm64)
            arch_type="aarch64" ;;
        amd64|x86_64)
            arch_type="x86_64" ;;
        *)
            log_error "不支持的CPU架构: $arch" ;;
    esac

    mysql_name="mysql-$MYSQL_VERSION-linux-$MYSQL_GLIBC-$arch_type"
    mysql_pkg_name="${mysql_name}.tar.xz"
    mysql_target_dir="$MYSQL_DATA_BASE/mysql-$MYSQL_VERSION"

    ### 获取MySQL包
    if curl --output /dev/null --silent --head --fail --connect-timeout 5 --max-time 10 "$OSS_BASE_URL"/health; then
        if [ ! -f "$mysql_pkg_name" ]; then
            log_info "在线安装MySQL, 访问 $OSS_BASE_URL/deploy/mysql/$mysql_pkg_name 进行下载"
            # curl -L -o "$mysql_pkg_name" "$OSS_BASE_URL/deploy/mysql/$mysql_pkg_name"
            wget -q "$OSS_BASE_URL/deploy/mysql/$mysql_pkg_name" || log_error "下载MySQL失败"
        fi
    else
        log_info "离线安装MySQL, 请上传 $mysql_pkg_name 到当前目录"
    fi

    ### 校验包
    [ -f "$mysql_pkg_name" ] || log_error "${mysql_pkg_name}不存在，请检查"

    ### 如果目标目录已存在，先删除旧目录（危险操作需确认）
    if [ -d "$mysql_target_dir" ]; then
        while :
        do
            read -p "目录 $mysql_target_dir 已存在，是否删除并重新安装？[Y/n]: " -r user_choice
            case "${user_choice}" in
                y|Y)
                    log_warn "确认删除目录: $mysql_target_dir"
                    rm -rf "$mysql_target_dir" || log_error "删除旧目录失败"
                    break
                    ;;
                n|N)
                    log_error "用户取消安装"
                    ;;
                *)
                    echo "无效输入，请输入 Y(y) 或 N(n)"
                    ;;
            esac
        done
    fi
    
    ### 解压MySQL
    log_info "解压MySQL"
    tar -xf "$mysql_pkg_name" -C "$MYSQL_DATA_BASE" --no-same-owner || log_error "解压失败"
    log_info "重命名MySQL"
    mv "$MYSQL_DATA_BASE"/"$mysql_name" "$mysql_target_dir" || log_error "重命名失败"
    
    ### 处理软链接（强制更新指向）
    if [ -L "$MYSQL_BASE_DIR" ]; then
        log_info "检测到旧软链接 $MYSQL_BASE_DIR，即将更新指向..."
        ln -sfn "$mysql_target_dir" "$MYSQL_BASE_DIR" || log_error "软链接更新失败"
    elif [ -e "$MYSQL_BASE_DIR" ]; then
        log_error "$MYSQL_BASE_DIR 已存在且不是软链接，请手动处理"
    else
        log_info "创建软链接 $MYSQL_BASE_DIR"
        ln -s "$mysql_target_dir" "$MYSQL_BASE_DIR" || log_error "软链接创建失败"
    fi

    ### 更改权限
    log_info "更改目录权限"
    chown "$MYSQL_USER":"$MYSQL_USER" -R "$MYSQL_DATA_BASE"

    ### 添加执行权限
    find "$MYSQL_BASE_DIR/bin" -type f -exec chmod 755 {} \;

    # 执行命令(openEuler操作系统可能会出现 mysql: error while loading shared libraries: libncurses.so.5: cannot open shared object file: No such file or directory)
    "$MYSQL_BASE_DIR"/bin/mysqld --version || log_error "命令执行异常，请先根据异常进行处理"
}

##############################################
# 初始化账号
##############################################
init_mysql() {

    /bin/cp -f "$MYSQL_BASE_DIR"/support-files/mysql.server /etc/rc.d/init.d/mysqld
    chmod 755 /etc/rc.d/init.d/mysqld
    chkconfig --add mysqld
    chkconfig mysqld on

    log_info "数据库初始化"
    "$MYSQL_BASE_DIR"/bin/mysqld --initialize
    if grep 'A temporary password is generated' "$MYSQL_LOG_DIR/mysqld.log"; then
        log_info "数据库初始化完成，获取初始密码！"
        local MYSQL_INIT_PASSWD
        MYSQL_INIT_PASSWD=$(grep 'A temporary password is generated' "$MYSQL_LOG_DIR"/mysqld.log|awk '{print $NF}')
    else
        log_error "未获取到初始密码，请检查异常日志"
    fi

    #  启动MySQL
    log_info "启动数据库"
    /etc/init.d/mysqld start || log_error "数据库启动失败"

    if ss -tuln | grep -q ":$MYSQL_PORT " >/dev/null; then

        log_info "数据库启动, 设置root， superadmin 账号密码, 两者密码一致"
        "$MYSQL_BASE_DIR"/bin/mysqladmin -uroot -p"$MYSQL_INIT_PASSWD" password "$MYSQL_ROOT_PASSWORD"
        
        log_info "创建管理员superadmin, 高权限账号admin, 主从复制账号repl_user, 并赋予相关权限"
        "$MYSQL_BASE_DIR"/bin/mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e "\
            CREATE USER 'superadmin'@'%' IDENTIFIED BY '$MYSQL_ROOT_PASSWORD'; \
            GRANT ALL PRIVILEGES ON *.* TO 'superadmin'@'%' WITH GRANT OPTION; \
            CREATE USER 'admin'@'%' IDENTIFIED BY '$MYSQL_ADMIN_PASSWORD'; \
            GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, \
            LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, \
            CREATE USER, EVENT, TRIGGER ON *.* TO 'admin'@'%' WITH GRANT OPTION; \
            CREATE USER 'repl_user'@'%' IDENTIFIED BY '$MYSQL_REPL_PASSWORD'; \
            GRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'%'; \
            FLUSH PRIVILEGES;"
        log_success "用户创建完成"
    else
        log_error "数据库启动失败"
    fi

}

# # 导入mysql-schema.sql时使用
# /usr/local/mysql/bin/mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e 'CREATE DATABASE IF NOT EXISTS nacos_server DEFAULT CHARSET utf8 COLLATE utf8_general_ci;'
# /usr/local/mysql/bin/mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e 'use nacos_server; source /data/nacos/conf/mysql-schema.sql;'
# /usr/local/mysql/bin/mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e 'show tables from nacos_server;'

##############################################
# 创建Nacos数据库
##############################################
create_database() {
    while :
    do
        read -p "是否创建Nacos数据库？[Y/n]: " -r user_choice
        case "${user_choice}" in
            y|Y)
                [ ! -f "$WORK_DIR/mysql-schema.sql" ] && log_error "mysql-schema.sql不存在，跳过创建数据库，结束安装，请手动创建！"
                log_info "创建Nacos数据库以及账号: nacos_server"
                "$MYSQL_BASE_DIR"/bin/mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e "\
                    CREATE DATABASE IF NOT EXISTS nacos_server DEFAULT CHARSET utf8 COLLATE utf8_general_ci; \
                    use nacos_server; source $WORK_DIR/mysql-schema.sql; show tables from nacos_server; \
                    CREATE USER 'nacos_server'@'%' IDENTIFIED BY '$MYSQL_NACOS_PASSWORD'; \
                    GRANT SELECT, INSERT, UPDATE, DELETE ON nacos_server.* TO 'nacos_server'@'%'; \
                    FLUSH PRIVILEGES;"
                log_success "Nacos数据库以及账号创建完成"
                break
                ;;
            n|N)
                log_info "跳过创建数据库,结束安装"
                break
                ;;
            *)
                log_warn "无效输入，请输入 Y(y) 或 N(n)"
                ;;
        esac
    done
}

##############################################
# 配置主从复制
##############################################
init_replication() {

    if [ "$(hostname -I|awk '{print $1}')" != "$MYSQL_MASTER_IP" ]; then
        log_info "当前主机是从库，配置主从复制"
        while :
        do
            log_info "等待连接主库..."
            if "$MYSQL_BASE_DIR"/bin/mysql -h "$MYSQL_MASTER_IP" -P "$MYSQL_PORT" -usuperadmin -p"$MYSQL_ROOT_PASSWORD" -e "select 1" >/dev/null 2>&1 ; then
                log_success "连接主库成功"
                break
            else
                log_warn "连接主库失败, 等待10秒后重试..."
                sleep 10
            fi
        done

        log_info "从主库获取备份文件"
        "$MYSQL_BASE_DIR"/bin/mysqldump -h "$MYSQL_MASTER_IP" -P "$MYSQL_PORT" -usuperadmin -p"$MYSQL_ROOT_PASSWORD" \
            --single-transaction --routines --triggers --events --all-databases --master-data=2 --set-gtid-purged=OFF > "$WORK_DIR"/mysql-backup.sql
        if [ ! -s "$WORK_DIR"/mysql-backup.sql ]; then
            log_error "备份文件获取失败"
        fi

        local master_log_file
        local master_log_pos

        master_log_file=$(grep -i 'CHANGE MASTER TO' "$WORK_DIR"/mysql-backup.sql | awk -F"'" 'NR==1 {print $2}')
        master_log_pos=$(grep -i 'CHANGE MASTER TO' "$WORK_DIR"/mysql-backup.sql | awk -F"=" 'NR==1 {print $3}'|cut -d';' -f1)

        if [ -z "$master_log_file" ] || [ -z "$master_log_pos" ]; then
            log_error "获取主库备份文件失败"
        fi

        log_info "导入备份文件"
        "$MYSQL_BASE_DIR"/bin/mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e "source $WORK_DIR/mysql-backup.sql"

        log_info "配置主从复制"
        "$MYSQL_BASE_DIR"/bin/mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e "\
            CHANGE MASTER TO \
            MASTER_HOST='$MYSQL_MASTER_IP', \
            MASTER_PORT=$MYSQL_PORT, \
            MASTER_USER='repl_user', \
            MASTER_PASSWORD='$MYSQL_REPL_PASSWORD', \
            MASTER_LOG_FILE='$master_log_file', \
            MASTER_LOG_POS=$master_log_pos; \
            START SLAVE;"

        log_info "检查主从复制状态"
        REPLICATION_INFO=$("$MYSQL_BASE_DIR"/bin/mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e "show slave status\G")
        if grep -q "Slave_IO_Running: Yes" <<< "$REPLICATION_INFO" && grep -q "Slave_SQL_Running: Yes" <<< "$REPLICATION_INFO"; then
            log_success "主从复制配置成功"
        else
            log_error "主从复制配置失败，请检查日志"
        fi     
    else
        log_success "当前为主库，结束部署！"
    fi
}

main() {

    ### 检查依赖
    check_dependency

    ### 获取Glibc版本
    get_glibc_version

    log_info "开始安装数据库"
    init_env
    init_conf
    install_mysql
    init_mysql
    log_success "数据库安装完成"

    ### 创建Nacos数据库
    create_database

    ### 配置主从复制
    init_replication
}

main